home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
networke
/
xfirepow.000
/
xfirepow
/
xfirepower-0.84
/
client
/
socket.c
< prev
Wrap
C/C++ Source or Header
|
1995-11-22
|
18KB
|
831 lines
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#ifdef _AIX
#include <sys/select.h>
#endif
#include "data.h"
#include "defs.h"
#include "struct.h"
#include "proto.h"
#include "packet.h"
#ifdef UDP_PROXY
int UdpProxyOpen(), UdpProxyRecv();
#endif
static int udpLocalPort = 0, udpServerPort = 0;
static int serveraddr = 0;
static int seq = 0;
static struct timeval last_ping;
void
callServer(port, server)
int port;
char *server;
{
int s;
struct sockaddr_in addr;
struct hostent *hp;
printf("Calling %s on port %d.\n", server, port);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("I can't create a socket\n");
exit(0);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if ((addr.sin_addr.s_addr = inet_addr(server)) == -1) {
if ((hp = gethostbyname(server)) == NULL) {
printf("Who is %s?\n", server);
exit(0);
} else {
addr.sin_addr.s_addr = *(long *) hp->h_addr;
}
}
if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
printf("Server not listening!\n");
exit(0);
}
printf("Got connection.\n");
sock = s;
}
int packetLength(char *buf)
{
switch(buf[0]) {
case S_MAPINFO:
return sizeof(s_mapinfo) + (buf[1] * buf[2]);
case S_PERSONAL:
return sizeof(s_personal);
case S_POSITIONS:
return sizeof(s_positions) + (buf[1]&0x7f) * sizeof(s_oneposition);
case S_MESSAGE:
return sizeof(s_message);
case S_PLAYERDATA:
return sizeof(s_playerdata);
case S_PLAYERSTATS:
return sizeof(s_playerstats);
case S_SHELLINFO:
return sizeof(s_shellinfo);
case S_MAPSQUARE:
return sizeof(s_mapsquare);
case S_FLAG:
return sizeof(s_flag);
case S_UDPREPLY:
return sizeof(s_udpreply);
case S_MOTDLINE:
return sizeof(s_motdline);
case S_TEAMOK:
return sizeof(s_teamok);
case S_MINE:
return sizeof(s_mine);
case S_PLAYERINFO:
case S_SHELL:
case S_LOGIN:
default:
return 4;
}
}
void handle_map(char *buf)
{
int x, y;
s_mapinfo *pack = (s_mapinfo *)buf;
char *recvmap;
map_info.m_width = pack->width;
map_info.m_height = pack->height;
strcpy(map_info.m_name, pack->name);
recvmap = buf+sizeof(s_mapinfo);
for(x=0;x<map_info.m_width;x++) {
for(y=0;y<map_info.m_width;y++) {
map[x][y] = recvmap[y*map_info.m_width + x];
}
}
map_pixel = 512/map_info.m_width;
if(300/map_info.m_height < map_pixel)
map_pixel = 300/map_info.m_height;
W_ResizeWindow(mapwin, map_info.m_width*map_pixel, map_info.m_height*map_pixel);
redrawmap = 1;
}
void handle_personal(char *buf)
{
s_personal *pack = (s_personal *)buf;
me->p_x = ntohs(pack->x) << 4;
me->p_y = ntohs(pack->y) << 4;
me->p_status = pack->status;
me->p_dir = pack->dir & 0xf0;
me->p_speed = pack->dir & 0x0f;
me->p_damage = pack->damage;
me->p_ammo = pack->ammo;
me->p_fuel = ntohs(pack->fuel);
me->p_mines = (pack->mines & 0x1f);
me->p_trees = (pack->mines >> 5);
}
void handle_positions(char *buf)
{
s_positions *pack = (s_positions *)buf;
int cx, cy, dx, dy, i;
player *p;
s_oneposition *pos = (s_oneposition *)(pack+1);
if(!(pack->num & 0x80)) {
cx = (me->p_x>>4)-WINWIDTH/2;
cy = (me->p_y>>4)-WINHEIGHT/2;
if(cx < 0) cx = 0;
else if(cx > GRIDWIDTH * map_info.m_width - WINWIDTH)
cx = GRIDWIDTH * map_info.m_width - WINWIDTH;
if(cy < 0) cy = 0;
else if(cy > GRIDHEIGHT * map_info.m_height - WINHEIGHT)
cy = GRIDHEIGHT * map_info.m_height - WINHEIGHT;
for(i=0;i<pack->num;i++) {
p = &players[(pos[i].num & 0x3f)];
dx = pos[i].lx;
dy = pos[i].ly;
if(pos[i].num & 0x80)
dx += 256;
if(pos[i].num & 0x40)
dy += 256;
p->p_x = (cx+dx) << 4;
p->p_y = (cy+dy) << 4;
p->p_dir = pos[i].dir;
}
} else {
for(i=0;i<(pack->num & 0x7f);i++) {
p=&players[(pos[i].num &0x3f)];
p->p_x = (pos[i].lx * GRIDWIDTH) << 4;
p->p_y = (pos[i].ly * GRIDWIDTH) << 4;
p->p_dir = pos[i].dir;
}
}
}
void handle_playerinfo(char *buf)
{
s_playerinfo *pack = (s_playerinfo *)buf;
if(pack->status == PDEAD && players[(int)pack->num].p_status == PALIVE)
players[(int)pack->num].p_expfuse = EXPFUSE;
players[(int)pack->num].p_status = pack->status;
players[(int)pack->num].p_team = pack->team;
redraw_player_win();
}
void handle_login(char *buf)
{
s_login *pack = (s_login *)buf;
me = &players[pack->num];
}
void handle_shell(char *buf)
{
s_shell *pack = (s_shell *)buf;
shell *s;
int cx, cy, dx, dy;
cx = (me->p_x>>4)-WINWIDTH/2;
cy = (me->p_y>>4)-WINHEIGHT/2;
if(cx < 0) cx = 0;
else if(cx > GRIDWIDTH * map_info.m_width - WINWIDTH)
cx = GRIDWIDTH * map_info.m_width - WINWIDTH;
if(cy < 0) cy = 0;
else if(cy > GRIDHEIGHT * map_info.m_height - WINHEIGHT)
cy = GRIDHEIGHT * map_info.m_height - WINHEIGHT;
dx = pack->lx;
dy = pack->ly;
if(pack->num & 0x80)
dx += 256;
if(pack->num & 0x40)
dy += 256;
s = &shells[(pack->num & 0x3f)];
s->s_x = (cx+dx) << 4;
s->s_y = (cy+dy) << 4;
s->s_owner = (pack->num & 0x3f);
}
void handle_message(char *buf)
{
s_message *pack = (s_message *)buf;
print_message(pack->message, pack->from, pack->to);
}
void handle_playerdata(char *buf)
{
s_playerdata *pack = (s_playerdata *)buf;
strncpy(players[pack->num].p_name, pack->name, 16);
players[pack->num].p_name[15] = 0;
redraw_player_win();
}
void handle_playerstats(char *buf)
{
s_playerstats *pack = (s_playerstats *)buf;
players[pack->num].p_wins = ntohl(pack->wins);
players[pack->num].p_losses = ntohl(pack->losses);
players[pack->num].p_kills = ntohl(pack->kills);
me->p_updateplayers |= (1 << pack->num);
}
void handle_shellinfo(char *buf)
{
s_shellinfo *pack = (s_shellinfo *)buf;
shells[pack->num].s_status = pack->status;
shells[pack->num].s_fuse = 0;
}
void handle_mapsquare(char *buf)
{
s_mapsquare *pack = (s_mapsquare *)buf;
map[pack->x][pack->y] = pack->value;
map_square(pack->x, pack->y);
}
void handle_flag(char *buf)
{
s_flag *pack = (s_flag *)buf;
flags[pack->num].f_team = pack->team;
flags[pack->num].f_x = ntohs(pack->x) << 4;
flags[pack->num].f_y = ntohs(pack->y) << 4;
}
void handle_UdpReply(char *buf)
{
s_udpreply *pack = (s_udpreply *)buf;
printf("Handling UDP Reply, server port = %d\n", ntohs(pack->port));
}
void handle_motdline(char *buf)
{
s_motdline *pack = (s_motdline *)buf;
add_motd_line(ntohs(pack->line), pack->text);
}
void handle_teamok(char *buf)
{
s_teamok *pack = (s_teamok *)buf;
teamOk = pack->teamok;
}
void handle_mine(char *buf)
{
s_mine *pack = (s_mine *)buf;
int n = ntohs(pack->num);
if(pack->status == MIEMPTY) {
mines[n].mi_status = MIEXPLODE;
mines[n].mi_fuse = 0;
} else {
mines[n].mi_x = ntohs(pack->x) << 4;
mines[n].mi_y = ntohs(pack->y) << 4;
mines[n].mi_status = pack->status;
}
}
void handle_ping(char *buf)
{
s_ping *pack = (s_ping *)buf;
struct timeval now;
int usecs;
char mbuf[80];
if(pack->seq != seq-1)
return;
gettimeofday(&now, 0);
usecs=now.tv_usec - last_ping.tv_usec;
usecs += 1000000 * (now.tv_sec - last_ping.tv_sec);
sprintf(mbuf, "Ping time: %dms", usecs/1000);
print_message(mbuf, M_SRV, me->p_num);
}
void doRead(int);
void doServer()
{
fd_set read_fds;
int s;
struct timeval tv;
FD_ZERO(&read_fds);
FD_SET(sock, &read_fds);
if(udpSock >= 0) {
FD_SET(udpSock, &read_fds);
}
tv.tv_sec = 0;
tv.tv_usec = UTIMER;
#if 0
while(1) {
if((s=select(32, &read_fds, 0, 0, &tv)) > 0) {
if(udpSock >= 0 && FD_ISSET(udpSock, &read_fds)) {
doRead(udpSock);
}
if(FD_ISSET(sock, &read_fds))
doRead(sock);
} else if(s == 0) {
break;
}
}
#else
if((s=select(32, &read_fds, 0, 0, &tv)) > 0) {
if(udpSock >= 0 && FD_ISSET(udpSock, &read_fds)) {
doRead(udpSock);
}
if(FD_ISSET(sock, &read_fds))
doRead(sock);
}
#endif
}
void doRead(int asock)
{
static char *buf;
int in, pos, r;
if(!buf)
buf = malloc(70000); /* I know it's stupid. A large map can be 64k, this was the
the easiest way to deal with it. I suppose I could send
the map one row per packet instead of one huge one... */
in = read(asock, buf, 1024);
if(in > 0) {
totalread += in;
pos = 0;
while(pos < in) {
#ifdef DEBUG
printf("Packet length = %d, pos=%d, in=%d\n", packetLength(buf+pos), pos, in);
#endif
while(in - pos < packetLength(buf+pos)) {
r = read(asock, buf+in, packetLength(buf+pos) - (in - pos));
if(r<=0) {
printf("Read error from server, exiting\n");
exit(0);
}
in += r;
totalread += r;
}
#ifdef DEBUG
printf("Handling packet type %d\n", buf[pos]);
#endif
switch(buf[pos]) {
case S_MAPINFO:
handle_map(&buf[pos]);
break;
case S_PERSONAL:
handle_personal(&buf[pos]);
break;
case S_POSITIONS:
handle_positions(&buf[pos]);
break;
case S_PLAYERINFO:
handle_playerinfo(&buf[pos]);
break;
case S_LOGIN:
handle_login(&buf[pos]);
break;
case S_SHELL:
handle_shell(&buf[pos]);
break;
case S_MESSAGE:
handle_message(&buf[pos]);
break;
case S_PLAYERDATA:
handle_playerdata(&buf[pos]);
break;
case S_PLAYERSTATS:
handle_playerstats(&buf[pos]);
break;
case S_SHELLINFO:
handle_shellinfo(&buf[pos]);
break;
case S_MAPSQUARE:
handle_mapsquare(&buf[pos]);
break;
case S_FLAG:
handle_flag(&buf[pos]);
break;
case S_UDPREPLY:
handle_UdpReply(&buf[pos]);
break;
case S_MOTDLINE:
handle_motdline(&buf[pos]);
break;
case S_TEAMOK:
handle_teamok(&buf[pos]);
break;
case S_MINE:
handle_mine(&buf[pos]);
break;
case S_PING:
handle_ping(&buf[pos]);
break;
default:
break;
}
pos += packetLength(buf+pos);
}
}
}
int read_map()
{
map_info.m_width = 0;
while(map_info.m_width == 0) {
doServer();
}
return 1;
}
void sendPacket(char *buf)
{
int len;
int asock;
asock = (udpSock >= 0) ? udpSock : sock;
switch(buf[0]) {
case C_LOGIN:
len = sizeof(c_login);
asock = sock;
break;
case C_MESSAGE:
len = sizeof(c_message);
asock = sock;
break;
case C_UDPREQUEST:
len = sizeof(c_udprequest);
asock = sock;
break;
case C_PING:
len = sizeof(c_ping);
break;
case C_STEERING:
case C_SHELL:
case C_COURSE:
case C_SPEED:
default:
len = 4;
break;
}
if(write(asock, buf, len) != len) {
printf("Connection to server lost, exiting\n");
quit = 1;
}
}
void sendLogin(char *name, char *login)
{
c_login pack;
pack.type = C_LOGIN;
strncpy(pack.name, name, 15);
pack.name[15] = 0;
strncpy(pack.login, login, 15);
pack.login[15] = 0;
pack.version = htons(CLIENTVERSION);
sendPacket((char *)&pack);
}
void sendSteering(int keys)
{
c_steering pack;
pack.type = C_STEERING;
pack.keys = keys;
sendPacket((char *)&pack);
}
void sendShell()
{
c_shell pack;
pack.type = C_SHELL;
sendPacket((char *)&pack);
}
void sendMessage(char *msg, int to)
{
c_message pack;
pack.type = C_MESSAGE;
pack.to = to;
strncpy(pack.message, msg, 79);
pack.message[79] = 0;
sendPacket((char *)&pack);
}
void sendCourse(int course)
{
c_course pack;
pack.type = C_COURSE;
pack.dir = (UCHAR)course;
sendPacket((char *)&pack);
}
void sendSpeed(int speed)
{
c_speed pack;
pack.type = C_SPEED;
pack.speed = speed;
sendPacket((char *)&pack);
}
void sendTeam(int team)
{
c_team pack;
pack.type = C_TEAM;
pack.team = team;
sendPacket((char *)&pack);
}
void sendMine()
{
c_mine pack;
pack.type = C_MINE;
sendPacket((char *)&pack);
}
void sendBuild(int terrain)
{
c_build pack;
pack.type = C_BUILD;
pack.terrain = terrain;
sendPacket((char *)&pack);
}
void sendPing()
{
c_ping pack;
pack.type = C_PING;
pack.seq = seq++;
sendPacket((char *)&pack);
gettimeofday(&last_ping, 0);
}
#define MAX_PORT_RETRY 10
static int
openUdpConn()
{
struct sockaddr_in addr;
struct hostent *hp;
int attempts;
#ifdef UDP_PROXY
if(useUdpProxy)
return UdpProxyOpen();
#endif
if (udpSock >= 0) {
fprintf(stderr, "xfirepower: tried to open udpSock twice\n");
return (0); /* pretend we succeeded (this could be bad) */
}
if ((udpSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("xfirepower: unable to create DGRAM socket");
return (-1);
}
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
errno = 0;
udpLocalPort = (getpid() & 32767) + (rand() % 256);
for (attempts = 0; attempts < MAX_PORT_RETRY; attempts++) {
while (udpLocalPort < 2048) {
udpLocalPort = (udpLocalPort + 10687) & 32767;
}
addr.sin_port = htons(udpLocalPort);
if (bind(udpSock, (struct sockaddr *) & addr, sizeof(addr)) >= 0)
break;
}
if (attempts == MAX_PORT_RETRY) {
perror("xfirepower: bind");
close(udpSock);
udpSock = -1;
return (-1);
}
/* determine the address of the server */
if (!serveraddr) {
if ((addr.sin_addr.s_addr = inet_addr(server)) == -1) {
if ((hp = gethostbyname(server)) == NULL) {
printf("Who is %s?\n", server);
} else {
addr.sin_addr.s_addr = *(long *) hp->h_addr;
}
}
serveraddr = addr.sin_addr.s_addr;
}
return (0);
}
static int
recvUdpConn()
{
fd_set readfds;
struct timeval to;
struct sockaddr_in from;
int fromlen, res;
char buf[1024];
#ifdef UDP_PROXY
if(useUdpProxy)
return UdpProxyRecv();
#endif
bzero(&from, sizeof(from)); /* don't get garbage if really broken */
/* we patiently wait until the server sends a packet to us */
/* (note that we silently eat the first one) */
fromlen = sizeof(from);
FD_ZERO(&readfds);
FD_SET(udpSock, &readfds);
to.tv_sec = 6; /* wait 3 seconds, then abort */
to.tv_usec = 0;
if ((res = select(32, &readfds, 0, 0, &to)) <= 0) {
if (!res) {
printf("UDP connection request timed out\n");
return (-1);
} else {
perror("select() before recvfrom()");
return (-1);
}
}
if (recvfrom(udpSock, buf, BUFSIZ, 0, (struct sockaddr *) & from, &fromlen) < 0) {
perror("recvfrom");
return (-1);
}
if (from.sin_addr.s_addr != serveraddr) {
/* safe? */
serveraddr = from.sin_addr.s_addr;
}
if (from.sin_family != AF_INET) {
;
}
udpServerPort = ntohs(from.sin_port);
if (connect(udpSock, (struct sockaddr *) & from, sizeof(from)) < 0) {
perror("xfirepower: unable to connect UDP socket after recvfrom()");
close(udpSock);
udpSock = -1;
return (-1);
}
return (0);
}
int
closeUdpConn()
{
if (udpSock < 0) {
fprintf(stderr, "xfirepower: tried to close a closed UDP socket\n");
return (-1);
}
shutdown(udpSock, 2);
close(udpSock);
udpSock = -1;
return 0;
}
void
sendUdpRequest(req)
int req;
{
c_udprequest packet;
packet.type = C_UDPREQUEST;
packet.mode = MODE_UDP;
if (openUdpConn() >= 0) {
/* send the request */
packet.type = C_UDPREQUEST;
packet.mode = MODE_UDP;
packet.port = htons((unsigned)udpLocalPort);
sendPacket((char *) & packet);
if (recvUdpConn() < 0) {
printf("Couldn't open UDP connection\n");
closeUdpConn();
}
}
}
#ifdef UDP_PROXY
int UdpProxyOpen()
{
int s, res;
struct sockaddr_in addr;
struct hostent *hp;
char buf[BUFSIZ], *ptr;
printf("Using \"%s\" as the UDP proxy server address.\n", proxyServer);
if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return(-1);
}
addr.sin_family = AF_INET;
addr.sin_port = htons(proxyPort);
if ((addr.sin_addr.s_addr = inet_addr(proxyServer)) == -1) {
if ((hp = gethostbyname(proxyServer)) == NULL) {
printf("Who is %s?\n", proxyServer);
return -1;
} else {
addr.sin_addr.s_addr = *(long *) hp->h_addr;
}
}
if (connect(s, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
printf("UDP Proxy server not listening!\n");
return -1;
}
printf("Got UDP Proxy connection.\n");
udpSock = s;
sprintf(buf, ": %s !", server);
write(udpSock, buf, strlen(buf));
ptr = buf - 1;
while((*ptr != '!') && ptr < buf + BUFSIZ - 1) {
ptr++;
loop:
if((res = read(udpSock, ptr, 1)) < 0) {
perror("read");
return -1;
}
if(res < 1) goto loop;
*(ptr+1) = 0;
}
if(sscanf(buf, "@ %d !", &udpLocalPort) != 1) {
printf("Couldn't scan UDP Proxy Local Port from \"%s\"\n", buf);
return -1;
}
return 0;
}
int UdpProxyRecv()
{
char buf[BUFSIZ];
sprintf(buf, "UDP recvUdpConn !");
write(udpSock, buf, strlen(buf));
if(read(udpSock, buf, 6) != 6) {
perror("read");
close(udpSock);
udpSock = -1;
}
if(strncmp(buf, "UDPGO!", 6) != 0) {
printf("UDP Proxy connection unsuccessful, result was \"%s\"\n", buf);
close(udpSock);
udpSock = -1;
}
return 0;
}
#endif